﻿using HXu.BaseTools;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace HXu.Test
{
    /**
     * 
        合理的使用System.Linq 类库，可以让代码更加高效简洁，对操作继承IEnumerable的数据类型（数组、List、Dictionary等）可以快速高效的做一些操作
        比如在字典中根据Value值获取对应的Key，常规方法就是遍历比较，使用Linq库的"FirstOrDefault"或"Where"则会更加快捷。

        Linq查询有两种形式的语法：查询语法和方法语法
            1. 查询语法：使用查询表达式的形式，类似SQL语句
                var value00 = from item in array1 select item;
            2. 方法语法：使用方法调用的形式
                value00 = array1.Select(item => item);
    */
    public class LinqFun : MonoBehaviour
    {
        public class Person
        {
            public string Id;
            public string Name;
            public int Age;

            public Person(string id, string name, int age)
            {
                this.Id = id;
                this.Name = name;
                this.Age = age;
            }
        }



        protected void Start()
        {
            List<Person> students = new List<Person>() { new Person("01", "HXu", 11), new Person("02", "HXu2", 12) };
            List<int> numbs = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

            //Select:指定对象的哪部分被选择（可以是整个数据项，也可以是其中的字段），并将结果序列合并为一个序列
            List<string> studentName = new List<string>(students.Select(item => item.Name));//指定选择name字段，返回值类型实际为IEnumerable<string>
            studentName.LogJoin();//"HXu","HXu2"

            //ForEach:获取列表中的某个字段值
            List<string> nameList = new List<string>();
            students.ForEach(person => { nameList.Add(person.Name);});
            nameList.LogJoin();//"HXu","HXu2"

            //Where:对序列的元素进行筛选
            var a = new List<int>(numbs.Where(item => item <= 5));//对num的元素进行筛选，取元素值<=5的元素
            a.LogJoin();//0,1,2,3,4,5

            //Take:返回序列中的前n个对象
            var b = new List<int>(numbs.Take(4));
            b.LogJoin();//0,1,2,3

            //Skip:跳过序列中的前n个对象
            var c = new List<int>(numbs.Skip(4));
            c.LogJoin();//4,5,6,7,8,9

            //Concat:连接两个序列
            var d = c.Concat(b);
            d.LogJoin();//4,5,6,7,8,9,0,1,2,3

            //OrderBy:根据一个或多个键对序列中的元素排序
            var e = d.OrderBy(index => index);
            e.LogJoin();//0,1,2,3,4,5,6,7,8,9

            //Reverse:反转序列中的元素
            var f = e.Reverse();
            f.LogJoin();//9,8,7,6,5,4,3,2,1,0

            //GroupBy:对序列中的元素分组
            var g = numbs.GroupBy(index => index <= 4);
            foreach (IGrouping<bool, int> item in g)
            {
                Debug.Log(item.Key);
                g.LogJoin();
                //True 0,1,2,3,4
                //False 5,6,7,8,9
            }

            //Distinct: 去除序列中的重复项
            var h = b.Concat(b);
            h.LogJoin();//0,1,2,3,0,1,2,3
            var i = h.Distinct();
            i.LogJoin();//0,1,2,3

            //Union:返回两个序列的并集
            var j = a.Union(c);//a:0,1,2,3,4,5;c:4,5,6,7,8,9;
            j.LogJoin();//0,1,2,3,4,5,6,7,8,9

            //Intersect:返回两个序列的交集
            var k = a.Intersect(c);//a:0,1,2,3,4,5;c:4,5,6,7,8,9;
            k.LogJoin();//4,5

            //First:返回序列中第一个匹配的元素。如果没有元素匹配，抛出异常。如果没有给出条件，返回序列的第一个元素
            //FirstOrDefault:返回序列中第一个匹配的元素。如果没有元素匹配，返回该类型的默认值。如果没有给出条件，返回序列的第一个元素

            var l = numbs.First();
            l.Log();         //0
            l = numbs.First(value => value > 2);
            l.Log();         //3
            l = numbs.FirstOrDefault(value => value >= 9);
            l.Log();         //9
            l = numbs.FirstOrDefault(value => value > 10);
            l.Log();         //0

            //Last:返回序列中最后一个匹配的元素。如果没有元素匹配，抛出异常。如果没有给出条件，返回序列的最后一个元素
            //LastOrDefault:返回序列中最后一个匹配的元素。如果没有元素匹配，就返回默认值。如果没有给出条件，返回序列的最后一个元素


            //ElementAt:返回序列中指定索引处的元素；如果索引超出范围，抛出异常
            //ElementAtOrDefault: 返回序列中指定索引处的元素；如果索引超出范围，返回默认值
            var m = numbs.ElementAt(1);
            m.Log();//1


            //Contains: 序列中是否包含给定的元素
            var n = numbs.Contains(1);
            n.Log();     //True

            //Count:返回序列中元素的个数(int)。重载可以添加筛选条件，返回满足条件的元素个数
            //LongCount: 返回序列中元素的个数(long)。重载可以添加筛选条件，返回满足条件的元素个数

            var o = numbs.Count();
            o.Log();     //10
            var p = numbs.LongCount(value => value < 3);
            p.Log();     //3

            //Sum:返回序列中值的总和
            var q = numbs.Sum();
            q.Log();     //45

            //Min:返回序列中最小的值
            //Max:返回序列中最大的值
            var r = numbs.Min();
            r.Log();     //0
            r = numbs.Max();
            r.Log();     //9

            //Average:返回序列中的平均值
            var s = numbs.Average();
            DebugTools.Log(s);     //2

            //Any:序列中是否存在满足条件的元素

            var t = numbs.Any(value => value > 0);
            DebugTools.Log(t);     //True
            
            //All:序列中是否全部元素都满足条件
            var u = numbs.All(value => value > 0);
            DebugTools.Log(u);     //False

            //Append: 将一个值追加到序列末尾
            List<int> v = new List<int>(numbs.Append(10));
            //var v = nums.Append(10);
            DebugTools.LogJoin(v);     //0,1,2,3,4,5,6,7,8,9,10
        }
    } 
}
